import socket
import news
import weather
from PyQt5.QtCore import QThread, pyqtSignal
from urllib import parse

def get_host_ip():
    """
    查询本机ip地址
    其他方法如gethostname+gethostaddr都是猜测ip地址。
    利用 UDP 协议来实现的，生成一个UDP包，把自己的 IP 放如到 UDP 协议头中，然后从UDP包中获取本机的IP。
这个方法并不会真实的向外部发包，所以用抓包工具是看不到的。但是会申请一个 UDP 的端口，所以如果经常调用也会比较耗时的
    :return: ip
    """
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    finally:
        s.close()

    return ip


def tcp():
    ip_port = ('172.22.64.31', 9999)
    s = socket.socket()
    s.bind(ip_port)
    s.listen(5)

    while True:
        print("server waiting...")
        conn, addr = s.accept()
        client_data = conn.recv(1024)
        print(client_data.decode('utf-8'))
        conn.getmsg("不要回答".encode('utf-8'))
        conn.close()

# class Tcp():
#     def __init__(self):
#         ip_port = ('127.0.0.1', 9999)
#         self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#         self.s.bind(ip_port)
#         self.s.listen(5)
#         print("tcp构造")
#
#     def connect(self):
#         self.conn, self.addr = self.s.accept()
#         print("内部连接")
#
#     def recv(self):
#         print("接收数据")
#         self.client_data = self.conn.recv(1024).decode('utf-8')
#         print(self.client_data)
#         return self.client_data
#
#
#     def getmsg(self):
#         # 获取到新闻 转换成字符串类型
#         self.news = news.getNews()
#         self.news = str(self.news)
#         # 获取到天气 转换成字符串类型
#         self.weather = weather.getWeather()
#         self.weather = str(self.weather)
#         # 将数据用‘//’拼接，自定义报文形式
#         self.msg = self.news + "//" + self.weather
#         return self.msg
#
#     def close(self):
#         self.conn.close()

class Tcp(QThread):
    """
    Tcp类，继承自QT的多线程类，可以将数据显示在前端界面。
    """

    """
    定义三个信号，将数据发送给前端显示的，str类型
    状态信号、接收数据信号、发送数据信号
    """
    state_signal = pyqtSignal(str)
    recv_signal = pyqtSignal(str)
    send_signal = pyqtSignal(str)

    def __init__(self):
        # 构造出socket的基本构架，ip地址+端口号
        super(Tcp, self).__init__()
        self.port = 9999
        self.ip_port = (get_host_ip(), self.port)
        # s是socket对象，ipv4+tcp协议
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        self.requestNum = 0
        print("tcp构造完成")
    # def connect(self):
    #     # self.conn, self.addr = self.s.accept()
    #     print(self.s.accept())
    #     print("内部连接")
    #
    # def recv(self):
    #     print("接收数据")
    #     self.client_data = self.conn.recv(1024).decode('utf-8')
    #     print(self.client_data)
    #     return self.client_data
    #
    #
    # def getmsg(self):
    #     # 获取到新闻 转换成字符串类型
    #     self.news = news.getNews()
    #     self.news = str(self.news)
    #     # 获取到天气 转换成字符串类型
    #     self.weather = weather.getWeather()
    #     self.weather = str(self.weather)
    #     # 将数据用‘//’拼接，自定义报文形式
    #     self.msg = self.news + "//" + self.weather
    #     return self.msg
    #
    # def send(self):
    #     self.conn.sendall(self.msg.encode('utf-8'))
    #
    # def close(self):
    #     self.conn.close()

    def run(self):
        # 绑定的部分 如果放在构造函数里会导致地址端口冲突， 所以放在线程执行方法里
        try:
            print(self.ip_port)
            self.s.bind(self.ip_port)
            self.s.listen(5)
        except:
            pass
        while True:
            print("连接")
            self.conn, self.addr = self.s.accept()

            # 做图形的更新  传递参数
            self.state_signal.emit("已连接{}:{}".format(self.addr[0], self.addr[1]))

            print("接收数据", self.addr)
            # self.client_data = self.conn.recv(1024).decode('utf-8')
            client = self.conn.recv(1024)
            print(client, type(client))
            # client = bytes(client,encoding='utf-8')
            # print(client, type(client))

            # 对数据（bytes）先转换成字符串 再解码 urldecode
            # self.client_data = parse.unquote(str(client, encoding='utf-8'))
            self.client_data = str(client, encoding='utf-8')
            print(type(self.client_data))
            print("tcp clientdata", self.client_data)

            recievedict = eval(self.client_data)

            string = "GET / HTTP / 1.1\nHost:{}\nStatus Code:200\nrequest:{}".format(recievedict['general']['Host'], recievedict['request'])
            self.recv_signal.emit(string)

            print("发送数据")

            # 获取到天气 转换成字符串类型
            self.weather = weather.getWeather(self.requestNum)
            self.weather = str(self.weather)
            self.response = {
                'header':{
                    'state':"HTTP / 1.1 200 OK",
                    'Content - Language': 'zh - CN',
                    'Content - Type': 'text / html;charset = UTF - 8'
                    },
                'weather': self.weather
                }

            # 获取到新闻 转换成字符串类型
            if recievedict['request'] == 'news':
                self.news = news.getNews()
                self.news = str(self.news)
                self.response['news'] = self.news

            else:
                self.response['data'] = '你好'
            # 请求次数+1 请求频繁会被暂时封掉
            self.requestNum += 1

            print(self.response)
            # 把要发送的数据 发送给前端
            self.send_signal.emit(str(self.response))
            # self.conn.sendall(self.msg.encode('utf-8'))
            # msg = parse.urlencode(self.msg)
            self.conn.sendall(bytes(str(self.response), encoding='utf-8'))
            self.conn.close()

class Udp(QThread):

    state_signal = pyqtSignal(str)
    recv_signal = pyqtSignal(str)
    send_signal = pyqtSignal(str)

    def __init__(self):
        super(Udp, self).__init__()
        self.port = 8000
        self.ip_port = (get_host_ip(), self.port)
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

        self.requestNum = 0

    def run(self):
        try:
            self.s.bind(self.ip_port)
        except:
            pass
        while True:
            print("udp接收数据")
            data, addr = self.s.recvfrom(1024)
            self.state_signal.emit("已接收{}:{}的数据".format(addr[0],addr[1]))

            # data = parse.unquote(str(data, encoding='utf-8'))
            data = str(data, encoding='utf-8')
            print("数据：",data, type(data))  # <str>

            recievedict = eval(data)
            string = "GET / HTTP / 1.1\nHost:{}\nStatus Code:200\nrequest:{}".format(recievedict['general']['Host'],recievedict['request'])

            self.recv_signal.emit(string)

            self.weather = weather.getWeather(self.requestNum)
            self.weather = str(self.weather)
            self.response = {
                'header': {
                    'state': "HTTP / 1.1 200 OK",
                    'Content - Language': 'zh - CN',
                    'Content - Type': 'text / html;charset = UTF - 8'
                },
                'weather': self.weather
            }

            # 获取到新闻 转换成字符串类型
            if recievedict['request'] == 'news':
                self.news = news.getNews()
                self.news = str(self.news)
                self.response['news'] = self.news

            else:
                self.response['data'] = '你好'

            self.requestNum += 1
            print("发送数据")
            self.send_signal.emit(str(self.response))
            self.s.sendto(bytes(str(self.response), encoding='utf-8'), addr)
            print("发送完毕")
        self.s.close()
